﻿using GN.Pay.Core.Values.Channel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Dependency;
using RabbitMQ.GNClient;
using RabbitMQ.GNClient.Events;
using GN.Pay.Core.Services;
using GN.Pay.Core.Entities;
using GN.Pay.Core.Values;
using Abp.AutoMapper;
using static GN.Pay.Core.Consts.ServiceConstant;
using GN.Pay.TradeChannel.Exceptions;

namespace GN.Pay.Core.Tasks.Queue.Impl
{
    /// <summary>
    /// 
    /// </summary>
    class ChannelRefundNotifyConsumerQueue : AConsumerQueue<TradeRefundApplyResultValue>, IChannelRefundNotifyConsumerQueue
    {

        public ChannelRefundNotifyConsumerQueue(IIocManager iocManager)
            : base(QueueType.ChannelRefundNotify, iocManager)
        {

        }

        /// <summary>
        /// 
        /// </summary>
        protected override ushort MaxPrefetchCount
        {
            get
            {
                return 10;
            }
        }

        protected override async Task Consumer(IEventingConsumer eventConsumer,
            TradeRefundApplyResultValue data,
            DeliverEventArgs e)
        {
            await Task.Run(() =>
            {
                if (string.IsNullOrWhiteSpace(e.Message.MessageId))
                {
                    this.Logger.ErrorFormat("通道退款通知无签名信息");
                    eventConsumer.Channel.Ack(e.DeliveryTag);
                    return;
                }
                if (!data.MessageSignVerify(Consts.Start.MessageSign, e.Message.MessageId))
                {
                    this.Logger.ErrorFormat("通道退款通知签名不正确");
                    eventConsumer.Channel.Ack(e.DeliveryTag);
                    return;
                }               
                bool isAck = true;
                try
                {
                    this.UpdateUnitOfWork(() =>
                    {
                        var tradeCacheService = this.IocManager.Resolve<ITradeCacheService>();
                        var tradeRefundBookService = this.IocManager.Resolve<ITradeRefundBookService>();
                        TradeRefundApply tradeRefundApply;
                        var account = tradeRefundBookService.Accounting(data, out tradeRefundApply);
                        if (tradeRefundApply != null && account != null)
                        {
                            var app = tradeCacheService.GetMerchantAppInfo(account.AppId);
                            if (app != null && !string.IsNullOrWhiteSpace(tradeRefundApply.NotifyUrl))
                            {
                                var notifyService = this.IocManager.Resolve<ITradeNotifyService>();
                                var message = account.MapTo<RefundNotifyData>();
                                message.ExtraParam = tradeRefundApply.ExtraParam;
                                message.TradeNo = tradeRefundApply.TradeNo;
                                message.Success = true;
                                message.StateMessage = "退款成功";
                                var channel = tradeCacheService.GetTradeChannel(account.AppId, account.ChannelId);
                                if (channel != null)
                                {
                                    message.ChannelName = channel.ChannelName;
                                }
                                else
                                {
                                    message.ChannelName = data.ChannelName;
                                }
                                var notify = notifyService.PullNotify(app, TradeNotifyType.Refund, tradeRefundApply.NotifyUrl, null, message);
                            }
                        }
                    });
                }
                catch (TradeChannelException err)
                {
                    isAck = false;
                    this.Logger.Error(err.Message, err);
                    eventConsumer.Channel.Ack(e.DeliveryTag);
                }
                catch (Exception err)
                {
                    isAck = false;
                    this.Logger.Error(err.Message, err);
                    this.DelayConsumer(eventConsumer, data, e, new TimeSpan(0, 0, 10));
                }
                finally
                {
                    if (isAck)
                    {
                        eventConsumer.Channel.Ack(e.DeliveryTag);
                    }
                }

            });
        }
    }
}
